/*
 * Thread Demos
 * Spring 2013 TCSS 558
 * Daniel M. Zimmerman
 */

package threads;

/**
 * A class that demonstrates the hazards of wait() and notify().
 * 
 * @author Daniel M. Zimmerman
 * @version Spring 2013
 */

public class Notify implements Runnable
{ 
  // Static Fields
  
  /**
   * The default number of threads.
   */
  public static final int DEFAULT_THREADS = 50;
    
  /**
   * The number of the Notify that should wake up.
   */
  
  private static int wake_number;
  
  // Instance Fields
  
  /**
   * The number of this Notify.
   */
  private final int my_number;
  
  // Constructor
  
  /**
   * Creates a Notify with the specified number.
   * 
   * @param the_number The number.
   */
  public Notify(final int the_number)
  { 
    my_number = the_number; 
  }
  
  // Instance Methods
  
  /**
   * Waits for my number to be awakened, and then prints that I was
   * notified and exits.
   */
  public void run()   
  {
    synchronized (Notify.class)
    { 
      while (my_number != wake_number)
      { 
        try
        {
          Notify.class.wait(); 
        }
        catch (final InterruptedException e)
        {
          System.err.println("We were interrupted!");
        }
      }
      
      System.out.println("Thread #" + my_number + " notified!");
      Notify.class.notifyAll();
    }
  }

  // Main Method
  
  /**
   * Creates 2 threads, and notifies once for each thread number.
   * 
   * @param the_args command line arguments, argument 0 is the
   * number of threads, others are ignored.
   */
  public static void main(final String[] the_args)
  {
    int number_of_threads = DEFAULT_THREADS;
    
    if (the_args.length > 0)
    {
      try
      {
        number_of_threads = Integer.parseInt(the_args[0]); 
      }
      catch (final NumberFormatException e)
      {
        number_of_threads = DEFAULT_THREADS;
      }
    }

    for (int i = 1; i <= number_of_threads; i++)
    {
      (new Thread(new Notify(i))).start();  
    }

    synchronized (Notify.class)
    { 
      for (int i = 1; i <= number_of_threads; i++)
      {
        Notify.wake_number = i;
        Notify.class.notifyAll();
        try
        {
          Notify.class.wait();
        }
        catch (final InterruptedException e)
        {
          // eek!
        }
      }
    }
  }
}
